//! @file   libcyan_internal.h
//! @brief  
//! @author Sayan Chaliha
//! @date   September, 2011
//!
//! 
#ifndef _LIBCYAN_INTERNAL_H
#define _LIBCYAN_INTERNAL_H

#ifdef HAVE_CONFIG_H
# include <lc_config.h>
#endif /* HAVE_CONFIG_H */

#ifndef HAVE_EXPLICIT
# define explicit
#endif /* HAVE_EXPLICIT */
#ifndef HAVE_MUTABLE
# define mutable
#endif /* HAVE_MUTABLE */
#ifndef HAVE_EXCEPTIONS
# undef LC_EXCEPTIONS
#endif /* HAVE_EXCEPTIONS */
#ifdef LOCK_READ
# undef LOCK_READ
#endif /* LOCK_WRITE */
#ifdef LOCK_WRITE
# undef LOCK_WRITE
#endif /* LOCK_WRITE */
#ifdef TEXT
# undef TEXT
#endif /* TEXT */
#if !defined (HAVE_CONST_CAST) || !defined (HAVE_STATIC_CAST) ||  \
    !defined (HAVE_REINTERPRET_CAST) || !defined (HAVE_DYNAMIC_CAST)
# error "C++ compiler whitout support for new-style casts?"
#endif /* HAVE_*_CAST */
#ifdef UNREFERENCED_PARAMETER
# undef UNREFERENCED_PARAMETER
#endif /* UNREFERENCED_PARAMETER */

#define TEXT(str)                   (str)
#define UNREFERENCED_PARAMETER(x)   ((void)(x))
#define MAX_RETRIES                 5
#define nullptr                     0

#ifdef DEBUG
# define assertTrue(x)            assert((x) == true)
# define assertFalse(x)           assert((x) == false)
# define assertEqual(x, y)        assert((x) == (y))
# define assertNotEqual(x, y)     assert((x) != (y))
# define assertNull(x)            assert((x) == nullptr)
# define assertNotNull(x)         assert((x) != nullptr)
# define assertGt(x, y)           assert((x) > (y))
# define assertNotGt(x, y)        assert(!((x) > (y)))
# define assertLt(x, y)           assert((x) < (y))
# define assertNotLt(x, y)        assert(!((x) < (y)))
# define assertGtOrEq(x, y)       assert((x) >= (y))
# define assertNotGtOrEq(x, y)    assert(!((x) >= (y)))
# define assertLtOrEq(x, y)       assert((x) <= (y))
# define assertNotLtOrEq(x, y)    assert(!((x) <= (y)))
#else
# define assertTrue(x)
# define assertFalse(x)
# define assertEqual(x, y)
# define assertNotEqual(x, y)
# define assertNull(x)
# define assertNotNull(x)
# define assertGt(x, y)
# define assertNotGt(x, y)
# define assertLt(x, y)
# define assertNotLt(x, y)
# define assertGtOrEq(x, y)
# define assertNotGtOrEq(x, y)
# define assertLtOrEq(x, y)
# define assertNotLtOrEq(x, y)
#endif /* DEBUG */

#ifdef HAVE___ATTRIBUTE__
# ifdef __CYAN_BUILD_DLL__
#   define CYAN_API              __attribute__((visibility ("default")))
#   define CYAN_HIDDEN           __attribute__((visibility ("hidden")))
# else
#   define CYAN_API              __attribute__((visibility ("default")))
#   define CYAN_HIDDEN
# endif /* __CYAN_BUILD__ */
# define CYAN_NORETURN           __attribute__((noreturn))
#elif defined (HAVE___DECLSPEC)
# ifdef __CYAN_BUILD_DLL__
#   define CYAN_API              __declspec(dllexport)
#   define CYAN_HIDDEN
# else
#   define CYAN_API              __declspec(dllimport)
#   define CYAN_HIDDEN
# endif /* __CYAN_BUILD */
# define CYAN_NORETURN           __declspec(noreturn)
#else
# define CYAN_API
# define CYAN_HIDDEN
# define CYAN_NORETURN
#endif /* HAVE___ATTRIBUTE__ */

#ifdef HAVE___FUNC__
# define LC_FUNCTION              __func__
#elif defined (HAVE___FUNCTION__)
# define LC_FUNCTION              __FUNCTION__
#else
# define LC_FUNCTION
#endif /* HAVE___FUNC__ */

#ifdef HAVE_PTHREAD
# define THREAD_SCOPE_GLOBAL      PTHREAD_SCOPE_SYSTEM
# define THREAD_SCOPE_LOCAL       PTHREAD_SCOPE_PROCESS
# define THREAD_STATE_JOINABLE    PTHREAD_CREATE_JOINABLE
# define THREAD_STATE_DETACHED    PTHREAD_CREATE_DETACHED
# ifndef PTHREAD_STACK_MIN
#   define PTHREAD_STACK_MIN      1024
# endif /* PTHREAD_STACK_MIN */
#elif defined (HAVE_WIN32_THREAD)
# define THREAD_SCOPE_GLOBAL
# define THREAD_SCOPE_LOCAL
# define THREAD_STATE_JOINABLE
# define THREAD_STATE_DETACHED
#else
# error "No suitable multi-threading API found!"
#endif /* HAVE_PTHREAD */

#ifndef LC_OS
# ifdef HOST_OS_DARWIN
#   define LC_OS_DARWIN
#   define LC_OS_UNIX_LIKE
# elif defined (HOST_OS_LINUX) || defined (HOST_OS_LINUX_GNU)
#   define LC_OS_LINUX
#   define LC_OS_UNIX_LIKE
# elif defined (_WIN32) || defined (_WIN64) || defined (HOST_OS_WIN)
#   define LC_OS_WINDOWS
#   define LC_OS_WINDOWS_
# else
#   error "Possibly unsupported OS!"
# endif /* HOST_OS_DARWIN */
# define LC_OS_NAME HOST_OS_TYPE
#endif /* LC_OS */

#ifndef LC_ARCH
# ifdef HOST_ARCH_X86_64
#   define LC_ARCH_X86_64
# elif defined (HOST_ARCH_I386)
#   define LC_ARCH_I386
# endif /* HOST_ARCH_X86_64 */
# define LC_ARCH HOST_ARCH_TYPE
#endif /* LC_ARCH */

# ifdef HAVE__VSNWPRINTF
#   define vswprintf                _vsnwprintf
# endif /* HAVE__VSNWPRINTF */
# ifdef HAVE__OPEN
#   define open                     _open
# endif /* HAVE__OPEN */
# ifdef HAVE__CLOSE
#   define close                    _close
# endif /* HAVE__CLOSE */
# ifdef HAVE__READ
#   define read                     _read
# endif /* HAVE__READ */
# ifdef HAVE__WRITE
#   define write                    _write
# endif /* HAVE__WRITE */
# ifdef HAVE__LCHMOD
#   define lchmod                   _lchmod
# endif /* HAVE__LCHMOD */
# ifdef HAVE__FCHMOD
#   define fchmod                   _fchmod
# endif /* HAVE__FCHMOD */
# ifdef HAVE__LSTAT
#   define lstat                    _lstat
# endif /* HAVE__LSTAT */
# ifdef HAVE__FSTAT
#   define fstat                    _fstat
# endif /* HAVE__FSTAT */
# ifdef HAVE__LSEEK
#   define lseek                    _lseek
# endif /* HAVE__LSEEK */
# ifdef HAVE__ACCESS
#   define access                   _access
# endif /* HAVE__ACCESS */
# ifdef HAVE__DUP
#   define dup                      _dup
# endif /* HAVE__DUP */

#ifndef LC_ATOMIC_BUILTINS
# ifdef HAVE___EXCHANGE_AND_ADD
#   define LC_GNU_ATOMIC_BUILTINS
#   define LC_ATOMIC_BUILTINS
# elif HAVE_INTERLOCKEDEXCHANGEADD
#   define LC_MSVC_ATOMIC_BUILTINS
#   define LC_ATOMIC_BUILTINS
# endif /* HAVE___EXCHANGE_AND_ADD */
#endif /* LC_ATOMIC_BUILTINS */

#ifndef HAVE_ISWASCII
# define iswascii(c)                (((c) & ~(0x7F)) == 0)
#endif /* HAVE_ISWASCII */

#ifdef LC_OS_UNIX_LIKE
# define TEMPORARY_FILE_NAME_PATTERN  "/tmp/libcyan.tmp.XXXXXX"

# define FILE_STAT_MT_MASK        S_IFMT
# define FILE_STAT_DIR_FLAG       S_IFDIR
# define FILE_STAT_REG_FLAG       S_IFREG
# define FILE_STAT_CHR_FLAG       S_IFCHR

# define FILE_ACCESS_EXISTS       F_OK
# define FILE_ACCESS_READ_OK      R_OK
# define FILE_ACCESS_WRITE_OK     W_OK
# define FILE_ACCESS_RW_OK        (R_OK | W_OK)
# define FILE_ACCESS_EXEC_OK      X_OK

# define FILE_MODE_READ_USER      S_IRUSR
# define FILE_MODE_WRITE_USER     S_IWUSR
# define FILE_MODE_EXEC_USER      S_IXUSR
# define FILE_MODE_RWX_USER       S_IRWXU
# define FILE_MODE_READ_GROUP     S_IRGRP
# define FILE_MODE_WRITE_GROUP    S_IWGRP
# define FILE_MODE_EXEC_GROUP     S_IXGRP
# define FILE_MODE_RWX_GROUP      S_IRWXG
# define FILE_MODE_READ_OTHER     S_IROTH
# define FILE_MODE_WRITE_OTHER    S_IWOTH
# define FILE_MODE_EXEC_OTHER     S_IXOTH
# define FILE_MODE_RWX_OTHER      S_IRWXO
# define FILE_MODE_DEFAULT        (S_IRWXU | S_IRGRP | \
                                  S_IXGRP | S_IROTH | S_IXOTH)

# define FILE_OPEN_READONLY       O_RDONLY
# define FILE_OPEN_WRITEONLY      O_WRONLY
# define FILE_OPEN_READWRITE      O_RDWR
# define FILE_OPEN_NONBLOCKING    O_NONBLOCK
# define FILE_OPEN_ASYNCHRONOUS   O_ASYNC
# define FILE_OPEN_NO_FOLLOW      O_NOFOLLOW
# define FILE_OPEN_APPEND         O_APPEND
# define FILE_OPEN_CREATE         O_CREAT
# define FILE_OPEN_TRUNCATE       O_TRUNC
# define FILE_OPEN_CREATE_EXCL    (O_CREAT | O_EXCL)
# define FILE_OPEN_EVENTS_ONLY    O_EVTONLY
# define FILE_OPEN_NO_CTTY        O_NOCTTY
# define FILE_OPEN_SYNCHRONOUS    O_DSYNC
# define FILE_OPEN_BINARY         0
# define FILE_OPEN_TEXT           0
# define FILE_OPEN_DEFAULT        O_RDONLY

#elif defined LC_OS_WINDOWS
# define TEMPORARY_FILE_NAME_PATTERN ""

# define FILE_STAT_MT_MASK        _S_IFMT
# define FILE_STAT_DIR_FLAG       _S_IFDIR
# define FILE_STAT_REG_FLAG       _S_IFREG
# define FILE_STAT_CHR_FLAG       _S_IFCHR

# define FILE_ACCESS_EXISTS       00
# define FILE_ACCESS_READ_OK      04
# define FILE_ACCESS_WRITE_OK     02
# define FILE_ACCESS_RW_OK        06
# define FILE_ACCESS_EXEC_OK      00

# define FILE_MODE_READ_USER      _S_IREAD
# define FILE_MODE_WRITE_USER     _S_IWRITE
# define FILE_MODE_EXEC_USER      0
# define FILE_MODE_RWX_USER       (_S_IREAD | _S_IWRITE)
# define FILE_MODE_READ_GROUP     _S_IREAD
# define FILE_MODE_WRITE_GROUP    _S_IWRITE
# define FILE_MODE_EXEC_GROUP     0
# define FILE_MODE_RWX_GROUP      (_S_IREAD | _S_IWRITE)
# define FILE_MODE_READ_OTHER     _S_IREAD
# define FILE_MODE_WRITE_OTHER    _S_IWRITE
# define FILE_MODE_EXEC_OTHER     0
# define FILE_MODE_RWX_OTHER      (_S_IREAD | _S_IWRITE)
# define FILE_MODE_DEFAULT        (_S_IREAD | _S_IWRITE)

# define FILE_OPEN_READONLY       _O_RDONLY
# define FILE_OPEN_WRITEONLY      _O_WRONLY
# define FILE_OPEN_READWRITE      _O_RDWR
# define FILE_OPEN_NONBLOCKING    0
# define FILE_OPEN_ASYNCHRONOUS   0
# define FILE_OPEN_NO_FOLLOW      0
# define FILE_OPEN_APPEND         _O_APPEND
# define FILE_OPEN_CREATE         _O_CREAT
# define FILE_OPEN_TRUNCATE       _O_TRUNC
# define FILE_OPEN_CREATE_EXCL    (_O_CREAT | _O_EXCL)
# define FILE_OPEN_EVENTS_ONLY    0
# define FILE_OPEN_NO_CTTY        0
# define FILE_OPEN_SYNCHRONOUS    0
# define FILE_OPEN_BINARY         _O_BINARY
# define FILE_OPEN_TEXT           _O_TEXT
# define FILE_OPEN_DEFAULT        (_O_RDONLY | _O_BINARY)
#endif /* LC_OS_UNIX_LIKE */

#endif /* _LIBCYAN_INTERNAL_H */
